#include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include "Types.h"
#include "Debug.h"
#include "Utili.h"
#include "Memory.h"

#if defined _DEBUG && defined _WIN32

#define MAX_MEM_REC		5000

typedef struct {
	void *Addr;
	Int32 Size;
} TMemRec;

static TMemRec _MemRecAry[MAX_MEM_REC];
static int _iMemAllocated = 0, _iMemCnt = 0;
static int _iMaxMemCnt = 0, _iMaxMemAllocated = 0;

static int ut_CmpMemAddr(const void* arg1, const void* arg2);

int ut_CmpMemAddr(const void* arg1, const void* arg2)
{
	TMemRec* ptr1 = (TMemRec*)arg1;
	TMemRec* ptr2 = (TMemRec*)arg2;

	if( (unsigned char*)(ptr1->Addr) > (unsigned char*)(ptr2->Addr) )
		return 1;
	else if( (unsigned char*)(ptr1->Addr) == (unsigned char*)(ptr2->Addr) )
		return 0;

	return -1;
}

int ut_GetMaxMemAllocatedSegmentCnt()
{
	return _iMaxMemCnt;
}

int ut_GetMaxMemAllocatedSize()
{
	return _iMaxMemAllocated;
}

#endif

// malloc release version, only log w/o assert
void* ut_malloc_rel(size_t size)
{
	char *p = NULL;

	if( size <= 0 )
	{
		LOG("ut_malloc: warning for allocating %d bytes!\n", size );
		return NULL;
	}

	p = (char*) malloc( size );

	if ( p == NULL )
		LOG("ut_malloc: %d failed!\n", size );

	return p;
}

// malloc debug version, assert when failed
void* ut_malloc_dbg(size_t size, const char *file, int line)
{
	static char str[128];

	char *p = NULL;

	if( size <= 0 )
	{
		LOG("ut_malloc: warning for allocating %d bytes!\n", size );
		return NULL;
	}

	p = (char*) malloc( size );

	if ( p == NULL || size <= 0 )
	{
		
		sprintf( str, "ut_malloc: %d bytes failed!\n", size );

		d_report( file, line, str );
	}

#if defined _DEBUG && defined _WIN32
	else
	{
		if( _iMemCnt <= 0 )
			memset( _MemRecAry, 0, sizeof( _MemRecAry ) );

		_iMemAllocated += size;

		_MemRecAry[_iMemCnt].Addr = p;
		_MemRecAry[_iMemCnt].Size = size;

		_iMemCnt ++;
		
		if( _iMemCnt > _iMaxMemCnt )
			_iMaxMemCnt = _iMemCnt;

		if( _iMemAllocated > _iMaxMemAllocated )
			_iMaxMemAllocated = _iMemAllocated;

		ASSERT_DEBUG( _iMemCnt < MAX_MEM_REC );

		qsort( _MemRecAry, _iMemCnt, sizeof( _MemRecAry[0] ), ut_CmpMemAddr );
	}
#endif

	return p;
}

void ut_free(void* ptr)
{
#if defined _DEBUG && defined _WIN32
	int idx;

	TMemRec* pRes = (TMemRec*) bsearch( &ptr, _MemRecAry, _iMemCnt, sizeof( TMemRec ), ut_CmpMemAddr );
	
	ASSERT_DEBUG( pRes );

 	idx =  (pRes - _MemRecAry );
	
	_iMemAllocated -= pRes->Size;

	ASSERT_DEBUG( _iMemAllocated >= 0 );

	if( idx < ( _iMemCnt - 1 ) )
		memmove( &_MemRecAry[idx], &_MemRecAry[idx+1], sizeof( TMemRec ) * ( _iMemCnt - ( idx + 1 ) ) );

	_iMemCnt--;

	ASSERT_DEBUG( _iMemCnt >= 0 );

	memset( &_MemRecAry[_iMemCnt], 0, sizeof( TMemRec ) );
#endif

	free( ptr );
}

#if __MEM_TEST__ 

//#include "PL1061/DebugTool.h"
//dgt_AvailableMemLog( "10-After-sp_Initialize");

#endif
